/*
 *  Copyright 2013 Utkin Dmitry
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */

#ifndef PROTOQTRPC_RPCCONTROLLER_H
#define PROTOQTRPC_RPCCONTROLLER_H

#include <string>
#include <QtGlobal>
#include <google/protobuf/service.h>


namespace protoqtrpc {

struct PeerInfo;

/**
 * An RpcController mediates a single method call.  The primary purpose of
 * the controller is to provide a way to manipulate settings specific to the
 * RPC implementation and to find out about RPC-level errors.
 */
class RpcController: public ::google::protobuf::RpcController
{
public:
    /**
     * @brief Constructs RpcController
     */
    RpcController();

    /**
     * @brief Destroys RpcController
     */
    virtual ~RpcController();

    // Client-side methods ---------------------------------------------
    // These calls may be made from the client side only.  Their results
    // are undefined on the server side (may crash).

    /**
     * Resets the RpcController to its initial state so that it may be reused in
     * a new call.  Must not be called while an RPC is in progress.
     */
    virtual void Reset();

    /**
     * After a call has finished, returns true if the call failed.  The possible
     * reasons for failure depend on the RPC implementation.  Failed() must not
     * be called before a call has finished.  If Failed() returns true, the
     * contents of the response message are undefined.
     */
    virtual bool Failed() const;

    /**
     * If Failed() is true, returns a human-readable description of the error.
     * @return description of the error
     */
    virtual std::string ErrorText() const;

    /**
     * Advises the RPC system that the caller desires that the RPC call be
     * canceled. If the call is canceled, the "done" callback will still be
     * called and the RpcController will indicate that the call failed at that time.
     */
    virtual void StartCancel();


    // Server-side methods ---------------------------------------------
    // These calls may be made from the server side only.  Their results
    // are undefined on the client side (may crash).

    /**
     * Causes Failed() to return true on the client side. "reason" will be
     * incorporated into the message returned by ErrorText().  If you find
     * you need to return machine-readable information about failures, you
     * should incorporate it into your response protocol buffer and should
     * NOT call SetFailed().
     * @param reason error message
     */
    virtual void SetFailed(const std::string& reason);

    /**
     * If true, indicates that the client canceled the RPC, so the server may
     * as well give up on replying to it.  The server should still call the
     * final "done" callback.
     * @return true if RPC was cancelled
     */
    virtual bool IsCanceled() const;

    /**
     * Asks that the given callback be called when the RPC is canceled.  The
     * callback will always be called exactly once.  If the RPC completes without
     * being canceled, the callback will be called after completion.  If the RPC
     * has already been canceled when NotifyOnCancel() is called, the callback
     * will be called immediately.
     *
     * NotifyOnCancel() must be called no more than once per request.
     *
     * @param callback Closure to run
     **/
    virtual void NotifyOnCancel(::google::protobuf::Closure* callback);

    /**
     * Gets peer info
     * @return peer info
     */
    const PeerInfo* peerInfo() const;

    /**
     * Sets peer info
     * @param peerInfo peer info
     */
    void setPeerInfo(const PeerInfo* peerInfo);

private:
    bool mFailed;
    bool mCanceled;
    std::string mErrorText;
    ::google::protobuf::Closure* mOnCancel;
    const PeerInfo* mPeerInfo;

private:
    Q_DISABLE_COPY(RpcController)
};

}

#endif
